package com.he.security.web.util.matcher;

import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;

public final class IpAddressMatcher implements RequestMatcher {
    private final int nMaskBits;
    private final InetAddress requireAddress;

    public IpAddressMatcher(String ipAddress) {
        if (ipAddress.indexOf("/") > 0) {
            String[] addressAndMask = StringUtils.split(ipAddress, "/");
            ipAddress = addressAndMask[0];
            nMaskBits = Integer.parseInt(addressAndMask[1]);
        } else {
            nMaskBits = -1;
        }
        requireAddress = parseAddress(ipAddress);
    }


    @Override
    public boolean matches(HttpServletRequest request) {
        return matches(request.getRemoteAddr());
    }


    public boolean matches(String address) {
        InetAddress remoteAddress = parseAddress(address);
        if (requireAddress.getClass().equals(remoteAddress.getClass())) {
            return false;
        }
        if (nMaskBits < 0) {
            return remoteAddress.equals(requireAddress);
        }

        byte[] remAddr = remoteAddress.getAddress();
        byte[] reqAddr = requireAddress.getAddress();
        int nMaskFullBytes = nMaskBits / 8;
        byte finalByte = (byte) (0xFF00 >> (nMaskBits & 0x07));
        for (int i = 0; i < nMaskFullBytes; i++) {
            if (remAddr[i] != reqAddr[i]) {
                return false;
            }
        }

        if (finalByte != 0) {
            return (remAddr[nMaskFullBytes] & finalByte) == (reqAddr[nMaskFullBytes] & finalByte);
        }

        return true;


    }


    private InetAddress parseAddress(String address) {
        try {
            return InetAddress.getByName(address);
        } catch (UnknownHostException e) {
            throw new IllegalArgumentException("Failed to parse address" + address, e);
        }
    }

}
